// @Date         2021-11-08
// @Author       Aaron Zhang
// @Description
// @FileName      container.go

package framework

import (
	"errors"
	"fmt"
	"sync"
)

type Container interface {
	Bind(provider ServiceProvider) error
	IsBind(key string) bool

	Make(key string) (interface{}, error)
	MustMake(key string) interface{}

	MakeNew(key string, params map[string]interface{}) (interface{}, error)

	ListProviders() map[string][]string
}

type FmkContainer struct {
	Container
	providers map[string]ServiceProvider //注册的服务容器
	instances map[string]interface{}     //实例化后的实体
	lock      sync.RWMutex               //锁
}

func NewFmkContainer() *FmkContainer {
	return &FmkContainer{
		providers: map[string]ServiceProvider{},
		instances: map[string]interface{}{},
		lock:      sync.RWMutex{},
	}
}

func (f *FmkContainer) ListProviders() map[string][]string {
	var result = map[string][]string{}

	var bind []string
	for k, _ := range f.providers {
		bind = append(bind, k)
	}

	var ins []string
	for k, _ := range f.instances {
		ins = append(ins, k)
	}
	result["bind"] = bind
	result["instance"] = ins
	return result
}

func (f *FmkContainer) Bind(provider ServiceProvider) error {
	//是否绑定过，判断重复
	if f.IsBind(provider.Name()) {
		return errors.New(fmt.Sprintf("%s已经存在，请检查", provider.Name()))
	}
	f.lock.Lock()
	//先把容器放到map对象里
	key := provider.Name()
	f.providers[key] = provider
	f.lock.Unlock()

	//是否绑定的时候就初始化
	if provider.IsDefer() == false {
		if err := provider.Boot(f); err != nil {
			return err
		}
		//实例化
		param := map[string]interface{}{
			"container": f,
		}
		params := provider.Params(param)
		ins, err := f.newInstance(provider, params, false)
		if err != nil {
			return err
		}
		f.instances[key] = ins
	}
	return nil
}

//IsBind 是否与容器进行了绑定
func (f *FmkContainer) IsBind(key string) bool {
	return f.findServiceProvider(key) != nil
}

//Make 进行实例化， 没参数，不强制实例化
func (f *FmkContainer) Make(key string) (interface{}, error) {
	return f.make(key, nil, false)
}

//MustMake 进行实例化，找不到则panic
func (f *FmkContainer) MustMake(key string) interface{} {
	instance, err := f.make(key, nil, false)
	if err != nil {
		panic(err)
	}
	return instance
}

// MakeNew 带参数进行实例化一个服务
func (f *FmkContainer) MakeNew(key string, params map[string]interface{}) (interface{}, error) {
	return f.make(key, params, true)
}

// make 内部真正的去实例化一个服务
func (f *FmkContainer) make(key string, params map[string]interface{}, forceNew bool) (interface{}, error) {
	f.lock.RLock()
	defer f.lock.RUnlock()

	//找不到服务实体，返回错误
	sp := f.findServiceProvider(key)
	if sp == nil {
		return nil, errors.New("contract " + key + " not register")
	}

	//是否已经实列
	ins := f.findInstanceProvider(key)
	if ins != nil {
		return ins, nil
	}

	//强制实例化的蚨，带着参数去实例化
	if forceNew {
		return f.newInstance(sp, params, true)
	}

	inst, err := f.newInstance(sp, params, true)
	if err != nil {
		return nil, err
	}
	f.instances[key] = ins
	return inst, nil
}

// PrintProviders 打印所有的服务
func (f *FmkContainer) PrintProviders() []string {
	var ret []string
	for _, v := range f.providers {
		ret = append(ret, v.Name())
	}
	return ret
}

//进行实例化
func (f *FmkContainer) newInstance(sp ServiceProvider, params map[string]interface{}, boot bool) (interface{}, error) {
	//boot先行， 进行一些配置的初始化
	if boot {
		if err := sp.Boot(f); err != nil {
			return nil, err
		}
	}
	//参数设置
	if params == nil {
		params = map[string]interface{}{
			"container": f,
		}
		params = sp.Params(params)
	}

	//register方法， 返回具体服务提供者的NewXXService
	method := sp.Register(f)
	ins, err := method(params)
	if err != nil {
		return nil, errors.New(err.Error())
	}

	return ins, nil
}

func (f *FmkContainer) findServiceProvider(key string) ServiceProvider {
	f.lock.RLock()
	defer f.lock.RUnlock()
	if sp, ok := f.providers[key]; ok {
		return sp
	}
	return nil
}

func (f *FmkContainer) findInstanceProvider(key string) interface{} {
	f.lock.RLock()
	defer f.lock.RUnlock()
	if sp, ok := f.instances[key]; ok {
		return sp
	}
	return nil
}
